{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "VGG\n",
    "https://github.com/minar09/VGG16-PyTorch/blob/master/vgg.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class VGG(nn.Module):\n",
    "    def __init__(self, \n",
    "                 in_channels = 1,\n",
    "                 cfg=[64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], \n",
    "                 num_classes=1000, \n",
    "                 init_weights=True):\n",
    "        super(VGG, self).__init__()\n",
    "\n",
    "        self.net = self._make_layers(cfg, in_channels)\n",
    "        \n",
    "        self.fc = nn.Sequential(\n",
    "            nn.Linear(512, 4096),\n",
    "            nn.ReLU(True),\n",
    "            nn.Dropout(),\n",
    "            nn.Linear(4096, 4096),\n",
    "            nn.ReLU(True),\n",
    "            nn.Dropout(),\n",
    "            nn.Linear(4096, num_classes),\n",
    "        )\n",
    "        \n",
    "        if init_weights:\n",
    "            self._initialize_weights()\n",
    "        \n",
    "        self.avgpool = nn.AdaptiveAvgPool2d(1)\n",
    "                    \n",
    "    def classifier(self, x):\n",
    "        x = self.avgpool(x)\n",
    "        x = x.view(x.size(0), -1)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "\n",
    "    def _make_layers(self, cfg, in_channels, batch_norm=False):\n",
    "        layers = []\n",
    "        in_channels = in_channels\n",
    "        for v in cfg:\n",
    "            if v == 'M':\n",
    "                layers.append(nn.MaxPool2d(kernel_size=2, stride=2))\n",
    "            else:\n",
    "                conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)\n",
    "                if batch_norm:\n",
    "                    layers.append(conv2d)\n",
    "                    layers.append(nn.BatchNorm2d(v))\n",
    "                    layers.append(nn.ReLU(inplace=True))\n",
    "                else:\n",
    "                    layers.append(conv2d)\n",
    "                    layers.append(nn.ReLU(inplace=True))\n",
    "                in_channels = v\n",
    "        return nn.Sequential(*layers)\n",
    "    \n",
    "    def _initialize_weights(self):\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, nn.Conv2d):\n",
    "                nn.init.kaiming_normal_(\n",
    "                    m.weight, mode='fan_out', nonlinearity='relu')\n",
    "                if m.bias is not None:\n",
    "                    nn.init.constant_(m.bias, 0)\n",
    "            elif isinstance(m, nn.BatchNorm2d):\n",
    "                nn.init.constant_(m.weight, 1)\n",
    "                nn.init.constant_(m.bias, 0)\n",
    "            elif isinstance(m, nn.Linear):\n",
    "                nn.init.normal_(m.weight, 0, 0.01)\n",
    "                nn.init.constant_(m.bias, 0)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.net(x)\n",
    "        x = self.classifier(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "inps = torch.randn((2, 1, 256, 256))\n",
    "vgg16 = VGG()\n",
    "out = vgg16(inps)\n",
    "\n",
    "out.size()"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
